﻿using RM.BasicLibrary.Attributes;
using RM.BasicLibrary.Exceptions;
using RM.BasicLibrary.Resources;
using System;
using System.Collections;
using System.Globalization;
using System.Reflection;

namespace RM.BasicLibrary
{
    /// <summary>
    /// Helper methods used throughout the codebase.
    /// </summary>
    public  static partial class Extension
    {
        /// <summary>
        /// Enforces that the provided object is non-null.
        /// </summary>
        /// <typeparam name="T">The type of value being checked.</typeparam>
        /// <param name="value">The value.</param>
        /// <returns><paramref name="value"/> if not null.</returns>
        public static T NotNull<T>([ValidatedNotNull]this T value, string nameOf = null)
        {
            if (value == null)
                throw new ParameterException(Root.BasicIns.Resource.GetValue(EnforceResources.CannotBeNull, nameOf ?? typeof(T).FullName));
            if (value is string)
                if (string.IsNullOrEmpty(value.ToString()) || string.IsNullOrWhiteSpace(value.ToString()))
                    throw new ParameterException(Root.BasicIns.Resource.GetValue(EnforceResources.CannotBeNull, nameOf ?? typeof(T).FullName));
            if (value.IsObjectGenericIEnumerable())
                if ((value as IList).Count == 0)
                    throw new ParameterException(Root.BasicIns.Resource.GetValue(EnforceResources.ElementCannotBeNull, nameOf ?? typeof(T).FullName));
            if (value is int && int.TryParse(value.ToString(), out int val))
                if (val == default(int))
                    throw new ParameterException(Root.BasicIns.Resource.GetValue(EnforceResources.NotDefault, nameOf ?? typeof(T).FullName));
            if(value is Action)
                throw new ParameterException(Root.BasicIns.Resource.GetValue(EnforceResources.CannotBeNull, nameOf ?? typeof(T).FullName));
            return value;
        }
        /// <summary>
        /// Enforce that the argument is a delegate type.
        /// </summary>
        /// <param name="delegateType">The type to test.</param>
        public static void ArgumentTypeIsFunction(this Type delegateType)
        {
            if (delegateType == null) throw new ArgumentNullException(nameof(delegateType));
            MethodInfo invoke = delegateType.GetTypeInfo().GetDeclaredMethod("Invoke");
            if (invoke == null)
                throw new ArgumentException(Root.BasicIns.Resource.GetValue(EnforceResources.NotDelegate, delegateType));
            if (invoke.ReturnType == typeof(void))
                throw new ArgumentException(Root.BasicIns.Resource.GetValue(EnforceResources.DelegateReturnsVoid, delegateType));
        }
    }
}
